<!DOCTYPE html>
<html lang="zh">
<head>
  <meta charset="UTF-8">
  <title>SVG平滑圆角按钮控制面板</title>
  <style>
    body {
      margin: 0;
      min-height: 100vh;
      display: flex;
      gap: 40px;
      align-items: flex-start;
      padding: 40px;
      background: #f5f5f5;
      font-family: sans-serif;
    }

    /* 控制面板样式 */
    .control-panel {
      background: white;
      padding: 20px;
      border-radius: 10px;
      box-shadow: 0 2px 10px rgba(0,0,0,0.1);
      position: sticky;
      top: 40px;
    }

    .control-group {
      margin-bottom: 15px;
    }

    .control-group label {
      display: block;
      margin-bottom: 5px;
      color: #666;
    }

    .control-row {
      display: flex;
      align-items: center;
      gap: 10px;
    }

    .control-row input[type="range"] {
      flex: 1;
    }

    .value-display {
      min-width: 40px;
      text-align: right;
      color: #666;
    }

    .corner-controls {
      display: grid;
      grid-template-columns: repeat(2, 1fr);
      gap: 10px;
    }

    .corner-control {
      display: flex;
      align-items: center;
      gap: 5px;
    }

    /* 按钮样式 */
    smooth-button {
      --button-width: 220px;
      --button-height: 70px;
      --border-radius: 20px;
      --curvature: 0.55;
      --stroke-width: 2px;
      --fill-color: #1d6cb7;
      --stroke-color: #0b4d8a;
      --hover-fill-color: #0b4d8a;
      --text-color: white;
      --font-size: 18px;
    }
  </style>
</head>
<body>
  <!-- 控制面板 -->
  <div class="control-panel">
    <div class="control-group">
      <label>按钮宽度</label>
      <div class="control-row">
        <input type="range" id="widthRange" min="100" max="400" value="220">
        <span class="value-display" id="widthValue">220px</span>
      </div>
    </div>

    <div class="control-group">
      <label>按钮高度</label>
      <div class="control-row">
        <input type="range" id="heightRange" min="40" max="200" value="70">
        <span class="value-display" id="heightValue">70px</span>
      </div>
    </div>

    <div class="control-group">
      <label>边框粗细</label>
      <div class="control-row">
        <input type="range" id="strokeRange" min="0" max="10" value="2" step="0.5">
        <span class="value-display" id="strokeValue">2px</span>
      </div>
    </div>

    <div class="control-group">
      <label>圆角大小</label>
      <div class="control-row">
        <input type="range" id="radiusRange" min="0" max="50" value="20">
        <span class="value-display" id="radiusValue">20px</span>
      </div>
    </div>

    <div class="control-group">
      <label>圆角控制</label>
      <div class="corner-controls">
        <div class="corner-control">
          <input type="checkbox" id="topLeftCorner" checked>
          <label for="topLeftCorner">左上角</label>
        </div>
        <div class="corner-control">
          <input type="checkbox" id="topRightCorner" checked>
          <label for="topRightCorner">右上角</label>
        </div>
        <div class="corner-control">
          <input type="checkbox" id="bottomLeftCorner" checked>
          <label for="bottomLeftCorner">左下角</label>
        </div>
        <div class="corner-control">
          <input type="checkbox" id="bottomRightCorner" checked>
          <label for="bottomRightCorner">右下角</label>
        </div>
      </div>
    </div>
  </div>

  <!-- 按钮预览 -->
  <smooth-button>预览按钮</smooth-button>

  <!-- Web Component 模板 -->
  <template id="smooth-button-template">
    <style>
      :host {
        display: inline-block;
      }
      .svg-button {
        width: var(--button-width, 220px);
        height: var(--button-height, 70px);
        position: relative;
      }
      .svg-button svg {
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
      }
      .svg-button path {
        fill: var(--fill-color, #1d6cb7);
        stroke: var(--stroke-color, #0b4d8a);
        stroke-width: var(--stroke-width, 2px);
        stroke-linejoin: round;
        stroke-linecap: round;
        transition: fill 0.2s;
      }
      .svg-button:hover path {
        fill: var(--hover-fill-color, #0b4d8a);
      }
      .svg-button text {
        pointer-events: none;
        font-size: var(--font-size, 18px);
        fill: var(--text-color, white);
        text-anchor: middle;
        dominant-baseline: middle;
      }
    </style>
    <div class="svg-button">
      <svg xmlns="http://www.w3.org/2000/svg">
        <defs>
          <clipPath id="button-mask">
            <path fill="white"></path>
          </clipPath>
        </defs>
        <g clip-path="url(#button-mask)">
          <path></path>
          <text x="110" y="35"><slot>按钮</slot></text>
        </g>
      </svg>
    </div>
  </template>

  <script>
    class SmoothButton extends HTMLElement {
      constructor() {
        super();
        this.attachShadow({ mode: 'open' });
        const template = document.getElementById('smooth-button-template');
        this.shadowRoot.appendChild(template.content.cloneNode(true));

        // 创建 MutationObserver 来监听样式变化
        this.observer = new MutationObserver(() => {
          this.updatePath();
        });
      }

      connectedCallback() {
        this.updatePath();
        // 开始监听样式变化
        this.observer.observe(this, {
          attributes: true,
          attributeFilter: ['style']
        });

        // 注册所有的CSS自定义属性
        if (window.CSS && CSS.registerProperty) {
          try {
            const properties = [
              '--border-radius',
              '--border-radius-top-left',
              '--border-radius-top-right',
              '--border-radius-bottom-right',
              '--border-radius-bottom-left',
              '--curvature',
              '--curvature-top-left',
              '--curvature-top-right',
              '--curvature-bottom-right',
              '--curvature-bottom-left'
            ];

            properties.forEach(prop => {
              CSS.registerProperty({
                name: prop,
                syntax: prop.includes('ratio') ? '<number>' : '<length>',
                inherits: true,
                initialValue: prop.includes('ratio') ? '0.55' : '20px'
              });
            });
          } catch (e) {
            // 属性可能已经注册
          }
        }
      }

      disconnectedCallback() {
        // 清理 observer
        this.observer.disconnect();
      }

      getCornerValues(styles, prefix) {
        const defaultValue = parseFloat(styles.getPropertyValue(`--${prefix}`));
        return {
          topLeft: parseFloat(styles.getPropertyValue(`--${prefix}-top-left`)) || defaultValue,
          topRight: parseFloat(styles.getPropertyValue(`--${prefix}-top-right`)) || defaultValue,
          bottomRight: parseFloat(styles.getPropertyValue(`--${prefix}-bottom-right`)) || defaultValue,
          bottomLeft: parseFloat(styles.getPropertyValue(`--${prefix}-bottom-left`)) || defaultValue
        };
      }

      updatePath() {
        const path = this.shadowRoot.querySelector('g path');
        const maskPath = this.shadowRoot.querySelector('#button-mask path');
        const svg = this.shadowRoot.querySelector('svg');
        const text = this.shadowRoot.querySelector('text');
        const styles = getComputedStyle(this);
        
        // 获取按钮实际尺寸
        const width = parseFloat(styles.getPropertyValue('--button-width')) || 220;
        const height = parseFloat(styles.getPropertyValue('--button-height')) || 70;
        
        // 更新 SVG viewBox
        const padding = 0;
        svg.setAttribute('viewBox', `${-padding} ${-padding} ${width + padding * 2} ${height + padding * 2}`);
        
        // 更新文字位置
        text.setAttribute('x', width / 2);
        text.setAttribute('y', height / 2);
        
        // 获取每个角的半径和曲率
        const radius = this.getCornerValues(styles, 'border-radius');
        const ratios = this.getCornerValues(styles, 'curvature');
        
        // 计算每个角的控制点偏移
        const d = {
          topLeft:     Math.min(radius.topLeft * ratios.topLeft,         radius.topLeft),
          topRight:    Math.min(radius.topRight * ratios.topRight,       radius.topRight),
          bottomRight: Math.min(radius.bottomRight * ratios.bottomRight, radius.bottomRight),
          bottomLeft:  Math.min(radius.bottomLeft * ratios.bottomLeft,   radius.bottomLeft)
        };
        
        // 生成路径数据
        const pathData = `
          M${radius.topLeft},0
          H${width - radius.topRight}
          C${width - radius.topRight + d.topRight},0 ${width},${radius.topRight - d.topRight} ${width},${radius.topRight}
          V${height - radius.bottomRight}
          C${width},${height - radius.bottomRight + d.bottomRight} ${width - radius.bottomRight + d.bottomRight},${height} ${width - radius.bottomRight},${height}
          H${radius.bottomLeft}
          C${radius.bottomLeft - d.bottomLeft},${height} 0,${height - radius.bottomLeft + d.bottomLeft} 0,${height - radius.bottomLeft}
          V${radius.topLeft}
          C0,${radius.topLeft - d.topLeft} ${radius.topLeft - d.topLeft},0 ${radius.topLeft},0
          Z`;

        // 更新两个路径
        path.setAttribute('d', pathData);
        maskPath.setAttribute('d', pathData);
      }
    }

    customElements.define('smooth-button', SmoothButton);

    // 控制面板逻辑
    const button = document.querySelector('smooth-button');
    
    // 尺寸控制
    const widthRange = document.getElementById('widthRange');
    const heightRange = document.getElementById('heightRange');
    const strokeRange = document.getElementById('strokeRange');
    const radiusRange = document.getElementById('radiusRange');
    
    // 显示值
    const widthValue = document.getElementById('widthValue');
    const heightValue = document.getElementById('heightValue');
    const strokeValue = document.getElementById('strokeValue');
    const radiusValue = document.getElementById('radiusValue');
    
    // 圆角控制
    const cornerControls = {
      topLeft: document.getElementById('topLeftCorner'),
      topRight: document.getElementById('topRightCorner'),
      bottomLeft: document.getElementById('bottomLeftCorner'),
      bottomRight: document.getElementById('bottomRightCorner')
    };

    // 更新按钮样式的函数
    function updateButtonStyle() {
      // 计算最大可用圆角半径
      const maxRadius = Math.min(widthRange.value, heightRange.value) / 2;
      // 限制圆角范围滑块的最大值
      radiusRange.max = maxRadius;
      // 如果当前值超过最大值，则调整为最大值
      if (radiusRange.value > maxRadius) {
        radiusRange.value = maxRadius;
      }
      
      // 更新尺寸
      button.style.setProperty('--button-width', `${widthRange.value}px`);
      button.style.setProperty('--button-height', `${heightRange.value}px`);
      button.style.setProperty('--stroke-width', `${strokeRange.value}px`);
      
      // 更新显示值
      widthValue.textContent = `${widthRange.value}px`;
      heightValue.textContent = `${heightRange.value}px`;
      strokeValue.textContent = `${strokeRange.value}px`;
      radiusValue.textContent = `${radiusRange.value}px`;
      
      // 更新圆角
      Object.entries(cornerControls).forEach(([corner, checkbox]) => {
        const cornerName = corner.replace(/([A-Z])/g, '-$1').toLowerCase();
        button.style.setProperty(
          `--border-radius-${cornerName}`, 
          checkbox.checked ? `${radiusRange.value}px` : '0'
        );
        button.style.setProperty(
          `--curvature-${cornerName}`,
          checkbox.checked ? '0.55' : '0'
        );
      });

    }

    // 添加事件监听
    [widthRange, heightRange, strokeRange, radiusRange].forEach(range => {
      range.addEventListener('input', updateButtonStyle);
    });

    Object.values(cornerControls).forEach(checkbox => {
      checkbox.addEventListener('change', updateButtonStyle);
    });

    // 初始化
    updateButtonStyle();
  </script>
</body>
</html>
